﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;
using System.Data;

namespace Txt2PajekLarge
{
    public enum Operating { VERTICES = 0, ARCS_OR_EDGES = 1 };

    class DataSaver
    {
        private bool blnAsyncCancelled = true;
        private bool blnSuspending = false;         //是否暂停，默认为“否”
        private BackgroundWorker oAsyncWorkerNodeList = null;
        private BackgroundWorker oAsyncWorkerEdgeList = null;
        private BackgroundWorker oAsyncWorkerFinalFile = null;
        private long[] data = { 0, 0, 0 };
        private string strLineForVer = "";
        private string strLineForEdge = "";
        private long lCntVertices = 0;
        private long lCntEdges = 0;
        private int nSleepTime = 1;

        private string VERTICES_HEAD_FILE = "vertices.head";
        private string VERTICES_FILE = "vertices.tmp";
        private string ARCS_FILE = "arcs.tmp";
        private string RESULT_FILE = "network.net";

        #region properties

        public bool AsyncCancelled
        {
            set { blnAsyncCancelled = value; }
            get { return blnAsyncCancelled; }
        }

        public string LineForVer
        {
            get { return strLineForVer; }
        }

        public string LineForEdge
        {
            get { return strLineForEdge; }
        }

        public bool Suspending
        {
            get { return blnSuspending; }
            set { blnSuspending = value; }
        }

        public BackgroundWorker AsyncWorkerNodeList
        { set { oAsyncWorkerNodeList = value; } }

        public BackgroundWorker AsyncWriterEdgeList
        { set { oAsyncWorkerEdgeList = value; } }

        public BackgroundWorker AsyncWriterFinalFile
        { set { oAsyncWorkerFinalFile = value; } }

        #endregion

        public void SaveNodes()
        {
            if (GlobalPool.Settings.Directed)
            {
                VERTICES_FILE = GlobalPool.SourceFileName+"_directed_" + VERTICES_FILE;
                VERTICES_HEAD_FILE = GlobalPool.SourceFileName + "_directed_" + VERTICES_HEAD_FILE;
            }
            else
            {
                VERTICES_FILE = GlobalPool.SourceFileName + "_undirected_" + VERTICES_FILE;
                VERTICES_HEAD_FILE = GlobalPool.SourceFileName + "_undirected_" + VERTICES_HEAD_FILE;
            }

            StreamWriter swVHeader = new StreamWriter(Application.StartupPath + "\\" + VERTICES_HEAD_FILE);
            StreamWriter swVertices = File.CreateText(Application.StartupPath + "\\" + VERTICES_FILE);
            try
            {
                blnAsyncCancelled = false;
                oAsyncWorkerNodeList.ReportProgress(0,"Waiting for nodes to save...");
                Thread.Sleep(nSleepTime);

                while (!GlobalPool.NodeList.IsCompleted)
                {
                    while (blnSuspending)    //pause
                    {
                        if (blnAsyncCancelled)
                        {
                            blnAsyncCancelled = true;
                            blnSuspending = false;
                            swVertices.Close();
                            swVertices.Dispose();
                            lCntVertices = 0;
                            return;
                        }
                        Thread.Sleep(50);
                    }
                    Node node;
                    if (GlobalPool.NodeList.TryTake(out node))
                    {
                        strLineForVer = node.NodeID.ToString() + "\t\"" + node.NodeName + "\"";
                        swVertices.WriteLine(strLineForVer);
                        lCntVertices++;

                        if ((lCntVertices & 16383) == 0)
                        {
                            oAsyncWorkerNodeList.ReportProgress(0, lCntVertices.ToString() + " vertices wrote.");
                            Thread.Sleep(nSleepTime);
                        }
                    }
                }//while

                swVHeader.WriteLine("*Vertices " + lCntVertices.ToString());

                if (blnAsyncCancelled) return;
                oAsyncWorkerNodeList.ReportProgress(0, "Saving nodes list over. \n" + VERTICES_HEAD_FILE + " and " + VERTICES_FILE + " generated.");
                Thread.Sleep(nSleepTime);
            }
            catch
            {
                throw;
            }
            finally
            {
                swVHeader.Close();
                swVHeader.Dispose();
                swVertices.Close();
                swVertices.Dispose();

                if (!GlobalPool.Settings.GenerateFinalFile)
                {
                    blnAsyncCancelled = true;
                    VERTICES_HEAD_FILE = "vertices.head";
                    VERTICES_FILE = "vertices.tmp";
                }
                blnSuspending = false;
                lCntVertices = 0;
            }
        }

        public void SaveEdges()
        {
            if (GlobalPool.Settings.Directed)
                ARCS_FILE = GlobalPool.SourceFileName + "_directed_" + ARCS_FILE;
            else
                ARCS_FILE = GlobalPool.SourceFileName + "_undirected_" + ARCS_FILE;

            StreamWriter swEdges = File.CreateText(Application.StartupPath + "\\" + ARCS_FILE);
            if (GlobalPool.Settings.Directed)
                swEdges.WriteLine("*Arcs");
            else
                swEdges.WriteLine("*Edges");

            try
            {
                blnAsyncCancelled = false;
                oAsyncWorkerEdgeList.ReportProgress(0,"Waiting for edges to save...");
                Thread.Sleep(nSleepTime);

                while (!GlobalPool.EdgeList.IsCompleted)
                {
                    while (blnSuspending)    //pause
                    {
                        if (blnAsyncCancelled)
                        {
                            blnAsyncCancelled = true;
                            blnSuspending = false;
                            swEdges.Close();
                            swEdges.Dispose();
                            lCntEdges = 0;

                            return;
                        }
                        Thread.Sleep(50);
                    }
                    Edge edge;
                    if (GlobalPool.EdgeList.TryTake(out edge))
                    {
                        strLineForEdge = edge.SourceNode.ToString() + "\t" + edge.TargetNode.ToString();
                        if (GlobalPool.Settings.WeightOnEdge) strLineForEdge += "\t" + edge.Weight.ToString();
                        swEdges.WriteLine(strLineForEdge);
                        lCntEdges++;
                        if ((lCntEdges & 16383) == 0)
                        {
                            oAsyncWorkerEdgeList.ReportProgress(0, lCntEdges.ToString() + " edges wrote.");
                            Thread.Sleep(nSleepTime);
                        }
                    }
                }//while

                oAsyncWorkerEdgeList.ReportProgress(0, "Saving arcs over. \n" + ARCS_FILE + " generated.");
                Thread.Sleep(nSleepTime);
            }
            catch
            {
                throw;
            }
            finally
            {
                swEdges.Close();
                swEdges.Dispose();

                if (!GlobalPool.Settings.GenerateFinalFile)
                {
                    blnAsyncCancelled = true;
                    ARCS_FILE = "arcs.tmp";
                }
                blnSuspending = false;
                lCntEdges = 0;
            }
        }

        public void GenerateFinalFile()
        {
            try
            {
                oAsyncWorkerFinalFile.ReportProgress(0, "Please wait while combining buffer files to result file named as \"" + RESULT_FILE + "\"...");
                Thread.Sleep(nSleepTime);
                PubHelper.ExecCommand("copy " + Application.StartupPath + "\\" + VERTICES_HEAD_FILE + "+" + Application.StartupPath + "\\" + VERTICES_FILE + "+" + Application.StartupPath + "\\" + ARCS_FILE + "=" + Application.StartupPath + "\\" + RESULT_FILE, "Y");

                if (blnAsyncCancelled) return;

                oAsyncWorkerFinalFile.ReportProgress(0, "Please wait while deleting buffer files...");
                Thread.Sleep(nSleepTime);

                PubHelper.ExecCommand("del " + Application.StartupPath + "\\" + VERTICES_HEAD_FILE, "Y");
                PubHelper.ExecCommand("del " + Application.StartupPath + "\\" + VERTICES_FILE, "Y");
                PubHelper.ExecCommand("del " + Application.StartupPath + "\\" + ARCS_FILE, "Y");

                oAsyncWorkerFinalFile.ReportProgress(0, "Transforming over. \nThe file " + RESULT_FILE + " has been generated.");
                Thread.Sleep(nSleepTime);
            }
            catch
            {
                throw;
            }
            finally
            {
                blnAsyncCancelled = true;
                blnSuspending = false;

                ARCS_FILE = "arcs.tmp";
                VERTICES_HEAD_FILE = "vertices.head";
                VERTICES_FILE = "vertices.tmp";
            }
        }
    }
}
